package game.frame;

import java.awt.Color;
import java.util.ArrayList;

public class Snake {
	protected ArrayList<CellPoint> snakeBody = new ArrayList<CellPoint>();
	private static Color bodyColor = new Color(255, 100, 100);
	private static Color headColor = Color.CYAN;
	private WorkPanelIfc wpIfc = null;
	private Direction dir;
	
	private boolean bitWrong;
	
	public Snake(int snakeLen, WorkPanel wp) {
		this.wpIfc = (WorkPanelIfc) wp;
		this.bitWrong = false;
		this.setDir(Direction.Right);
		
		//-- Initializing the snake body
		int maxLen = wpIfc.getHeight() / wpIfc.getCellSize()
					* wpIfc.getHeight() / wpIfc.getCellSize() - 2;
		if(snakeLen < 6) {
			snakeLen = 6;
		}
		if(snakeLen > maxLen) {
			snakeLen = maxLen;
		}
		
		int posX = (wpIfc.getWidth() / wpIfc.getCellSize() -  snakeLen) / 2;
		int posY = (wpIfc.getHeight()/ wpIfc.getCellSize() - 2) / 2;
		for(int i = posX; i < posX + snakeLen; i++) {
			snakeBody.add(new CellPoint(i, posY, bodyColor, wpIfc));
		}
		
		setHead();
	}
	
	private void setHead() {		
		snakeBody.get(snakeBody.size() - 1).setColor(headColor);
	}
	
	private void setBody() {
		snakeBody.get(snakeBody.size() - 1).setColor(bodyColor);
	}
	
	public boolean snakeMove(int mode, Direction dir) {
		boolean moved = false;
		switch (mode) {
		case 1:
			moved = snakeMove_Mode1(dir);
			break;
		case 2:
			moved = snakeMove_Mode2(dir);
			break;
			
		default:
			break;
		}
		
		return moved;
	}
	
	private boolean snakeMove_Mode1(Direction dir) {
		boolean moved = false;
		CellPoint head = snakeBody.get(snakeBody.size() - 1);
		int x = head.getX();
		int y = head.getY();
		
		switch (dir) {
		case Up:
			if(y-- < 0) {
				return moved;  //-- go up y--
			}
			
			moved = snakeMoveSupport(new CellPoint(x, y, wpIfc), dir);
			break;
		case Down:
			if(y++ > wpIfc.getHeight() / wpIfc.getCellSize() - 1) {
				return moved; //-- go down y++
			}
			
			moved = snakeMoveSupport(new CellPoint(x, y, wpIfc), dir);
			break;
		case Left:
			if(x-- < 0) {
				return moved; //-- go left x--
			}
			
			moved = snakeMoveSupport(new CellPoint(x, y, wpIfc), dir);
			break;
		case Right:
			if(x++ > wpIfc.getWidth() / wpIfc.getCellSize() - 1) {
				return moved; //-- go right x++
			}
			
			moved = snakeMoveSupport(new CellPoint(x, y, wpIfc), dir);
			break;

		default:
			break;
		}
		
		return moved;
	}
	
	private boolean snakeMove_Mode2(Direction dir) {
		boolean moved = false;
		CellPoint head = snakeBody.get(snakeBody.size() - 1);
		int x = head.getX();
		int y = head.getY();
		
		switch (dir) {
		case Up:
			if(--y < 0) {
				y = CellPoint.getMaxY();  //-- go up y--
			}
			
			moved = snakeMoveSupport(new CellPoint(x, y, wpIfc), dir);
			break;
		case Down:
			if(++y > CellPoint.getMaxY()) {
				y = 0; //-- go down y++
			}
			
			moved = snakeMoveSupport(new CellPoint(x, y, wpIfc), dir);
			break;
		case Left:
			if(--x < 0) {
				x = CellPoint.getMaxX(); //-- go left x--
			}
			
			moved = snakeMoveSupport(new CellPoint(x, y, wpIfc), dir);
			break;
		case Right:
			if(++x > CellPoint.getMaxX()) {
				x = 0; //-- go right x++
			}
			
			moved = snakeMoveSupport(new CellPoint(x, y, wpIfc), dir);
			break;

		default:
			break;
		}
		
		return moved;
	}
	
	private boolean snakeMoveSupport(CellPoint head, Direction dir) {
		boolean move = false;
		CellPoint nake = snakeBody.get(snakeBody.size() - 2);
		
		if(! snakeBody.contains(head)) {
			setBody(); //-- remove current head
			snakeBody.add(head);
			
			setHead();
			setDir(dir);
			
			//-- snake eat food
			if(head.equals(wpIfc.getSnakeFood().getFood())) {
				wpIfc.getSnakeFood().setRandomPosition(wpIfc);
				
				System.out.println("Good ! :)  Len = " + snakeBody.size());
			}
			else {
				snakeBody.remove(0);
			}
			
			move = true;
		}
		else if (! head.equals(nake)) {
			bitWrong = true;
			System.out.println("Snake bit wrong thing  Oh o o..!");
			snakeBody.remove(0);
		}
		else if (head.equals(nake)) {
			System.out.println("Are you crazy ? Snake cannot climb backward.");
		}
		
		return move;
	}

	public ArrayList<CellPoint> getSnakeBody() {
		return this.snakeBody;
	}
	public Direction getDir() {
		return dir;
	}

	private void setDir(Direction dir) {
		this.dir = dir;
	}

	public void setSnakeBody(ArrayList<CellPoint> snakeBody) {
		this.snakeBody = snakeBody;
	}

	public boolean isBitWrong() {
		return bitWrong;
	}
}
